import { checkAppVersion, type AppVersionCheckResult } from '@/Api/app'
import envConfig from '@/config/env'

let checkingUpdate = false

export interface CachedVersionInfo {
  versionName?: string
  versionCode?: number
  updateType?: string
  timestamp?: number
}

export const VERSION_STORAGE_KEY = 'app_latest_version_info'

/**
 * 保存最新版本信息到本地
 */
function persistLatestVersion(info: AppVersionCheckResult) {
  try {
    if (typeof uni === 'undefined') return
    if (!info.versionName && (info.versionCode === undefined || info.versionCode === null)) return
    const payload: CachedVersionInfo = {
      versionName: info.versionName,
      versionCode: info.versionCode,
      updateType: info.updateType,
      timestamp: Date.now(),
    }
    uni.setStorageSync(VERSION_STORAGE_KEY, payload)
  } catch (error) {
    console.warn('[AppUpdate] 缓存版本信息失败:', error)
  }
}

/**
 * 获取本地缓存的版本信息
 */
export function getCachedVersionInfo(): CachedVersionInfo | null {
  try {
    if (typeof uni === 'undefined') return null
    const cache = uni.getStorageSync(VERSION_STORAGE_KEY)
    return cache || null
  } catch (error) {
    console.warn('[AppUpdate] 读取缓存版本信息失败:', error)
    return null
  }
}

/**
 * 清除本地缓存的版本信息
 */
export function clearCachedVersionInfo() {
  try {
    if (typeof uni === 'undefined') return
    uni.removeStorageSync(VERSION_STORAGE_KEY)
  } catch (error) {
    console.warn('[AppUpdate] 清除缓存版本信息失败:', error)
  }
}

/**
 * App 版本更新检查
 */
export async function checkAppUpdate(): Promise<void> {
  // #ifdef APP-PLUS
  console.log('[AppUpdate] start checkAppUpdate')
  if (checkingUpdate) return
  checkingUpdate = true
  try {
    const systemInfo = uni.getSystemInfoSync()
    const platform = systemInfo.platform === 'ios' ? 'ios' : 'android'

    // @ts-ignore
    const runtimeVersionCode =
      typeof plus.runtime.versionCode === 'number'
        ? plus.runtime.versionCode
        : parseInt(plus.runtime.versionCode || '0', 10) || 0

    const cache = getCachedVersionInfo()
    // @ts-ignore
    const runtimeVersionName =
      typeof plus.runtime.version === 'string' && plus.runtime.version ? plus.runtime.version : ''
    const versionNameParam = cache?.versionName || runtimeVersionName || undefined

    const channel = getAppChannel()
    console.log('[AppUpdate] params =>', platform, runtimeVersionCode, versionNameParam, channel)
    const response = await checkAppVersion({
      platform,
      versionCode: runtimeVersionCode,
      versionName: versionNameParam,
      channel,
    })

    console.log('[AppUpdate] response =>', response)

    if (!response || response.code !== 200 || !response.data || !response.data.hasUpdate) {
      console.log('[AppUpdate] no update, stop')
      return
    }

    await handleUpdate(response.data, platform)
  } catch (error) {
    console.error('[AppUpdate] 检查更新失败:', error)
  } finally {
    checkingUpdate = false
  }
  // #endif
}

/**
 * 获取渠道标识（可根据项目需求扩展）
 */
function getAppChannel(): string | undefined {
  // 预留渠道配置，默认为空
  // 可通过 manifest.json 配置 arguments，或在 env 中配置
  if ((envConfig as any).channel) {
    return String((envConfig as any).channel)
  }
  return undefined
}

/**
 * 处理更新流程
 */
async function handleUpdate(info: AppVersionCheckResult, platform: string): Promise<void> {
  // wgt 更新：直接下载安装，不需要用户确认
  if (info.updateType === 'wgt') {
    try {
      await downloadAndInstallWgt(info)
    } catch (error: any) {
      console.error('[AppUpdate] wgt更新失败:', error)
      const retry = await showRetryDialog(
        error?.message || '更新失败，请检查网络后重试',
        info.forceUpdate,
      )
      if (retry) {
        await handleUpdate(info, platform)
      } else if (info.forceUpdate) {
        // @ts-ignore
        plus.runtime.quit()
      }
    }
    return
  }

  // 其他更新类型（apk/ipa）：需要用户确认
  const content = buildUpdateContent(info)
  const confirm = await showUpdateDialog(info, content)

  if (!confirm) {
    if (info.forceUpdate) {
      // @ts-ignore
      plus.runtime.quit()
    }
    return
  }

  try {
    if (info.updateType === 'apk') {
      if (platform === 'android') {
        await downloadAndInstallApk(info)
      } else {
        openExternalUrl(info.downloadUrl)
      }
    } else if (info.updateType === 'ipa') {
      openExternalUrl(info.downloadUrl)
    } else {
      // 未知类型，直接打开下载链接
      openExternalUrl(info.downloadUrl)
    }
  } catch (error: any) {
    console.error('[AppUpdate] 更新失败:', error)
    const retry = await showRetryDialog(
      error?.message || '更新失败，请检查网络后重试',
      info.forceUpdate,
    )
    if (retry) {
      await handleUpdate(info, platform)
    } else if (info.forceUpdate) {
      // @ts-ignore
      plus.runtime.quit()
    }
  }
}

/**
 * 构建更新内容
 */
function buildUpdateContent(info: AppVersionCheckResult): string {
  if (info.updateNotes && info.updateNotes.length > 0) {
    return info.updateNotes.join('\n')
  }
  if (info.updateDesc && info.updateDesc.trim().length > 0) {
    return info.updateDesc
  }
  return '发现新版本，建议立即更新以获得更好的体验。'
}

/**
 * 显示更新提示弹窗
 */
function showUpdateDialog(info: AppVersionCheckResult, content: string): Promise<boolean> {
  return new Promise((resolve) => {
    const title = `发现新版本 ${info.versionName ?? ''}`.trim()
    uni.showModal({
      title: title || '版本更新提醒',
      content,
      confirmText: '立即更新',
      cancelText: info.forceUpdate ? '退出应用' : '稍后',
      showCancel: !info.forceUpdate,
      success: (res) => {
        resolve(res.confirm === true)
      },
      fail: () => resolve(false),
    })
  })
}

/**
 * 显示失败提示
 */
function showRetryDialog(message: string, forceUpdate?: boolean): Promise<boolean> {
  return new Promise((resolve) => {
    uni.showModal({
      title: '更新失败',
      content: message,
      confirmText: '重试',
      cancelText: forceUpdate ? '退出应用' : '取消',
      showCancel: true,
      success: (res) => {
        if (res.confirm) resolve(true)
        else resolve(false)
      },
      fail: () => resolve(false),
    })
  })
}

/**
 * 下载并安装 wgt 包
 */
function downloadAndInstallWgt(info: AppVersionCheckResult): Promise<void> {
  return new Promise((resolve, reject) => {
    if (!info.downloadUrl) {
      reject(new Error('更新地址为空'))
      return
    }

    // @ts-ignore
    let waiting: any = plus.nativeUI.showWaiting('下载中 0%', {
      modal: true,
      back: 'none',
    })
    let lastPercent = -1

    // @ts-ignore
    const downloadTask = plus.downloader.createDownload(
      info.downloadUrl,
      {
        filename: `_doc/update/${Date.now()}.wgt`,
      },
      (download, status) => {
        if (waiting) {
          waiting.close()
          waiting = null
        }
        if (status === 200) {
          if (!download.filename) {
            reject(new Error('安装包路径不存在'))
            return
          }
          installWgt(download.filename, info).then(resolve).catch(reject)
        } else {
          reject(new Error(`下载安装包失败（状态码：${status}）`))
        }
      },
    )

    downloadTask.addEventListener('statechanged', (task: any) => {
      if (task.state === 3) {
        const percent = calcProgress(task.downloadedSize, task.totalSize || info.fileSize || 0)
        if (waiting && percent !== lastPercent) {
          waiting.setTitle(`下载中 ${percent}%`)
          lastPercent = percent
        }
      }
    })

    downloadTask.start()
  })
}

/**
 * 安装 wgt 包
 */
function installWgt(filePath: string, info: AppVersionCheckResult): Promise<void> {
  return new Promise((resolve, reject) => {
    uni.showLoading({ title: '安装更新...', mask: true })
    // @ts-ignore
    plus.runtime.install(
      filePath,
      { force: true },
      () => {
        uni.hideLoading()
        persistLatestVersion(info)
        // 构建更新内容
        const updateContent = buildUpdateContent(info)
        const title = `更新完成 ${info.versionName ?? ''}`.trim() || '更新完成'
        uni.showModal({
          title,
          content: updateContent || '应用需要重启以应用最新版本',
          showCancel: false,
          success: () => {
            // @ts-ignore
            plus.runtime.restart()
          },
        })
        resolve()
      },
      (error: any) => {
        uni.hideLoading()
        reject(new Error(`安装失败(${error.code}): ${error.message ?? ''}`))
      },
    )
  })
}

/**
 * 下载并安装 apk
 */
function downloadAndInstallApk(info: AppVersionCheckResult): Promise<void> {
  return new Promise((resolve, reject) => {
    if (!info.downloadUrl) {
      reject(new Error('更新地址为空'))
      return
    }

    // @ts-ignore
    let waiting: any = plus.nativeUI.showWaiting('下载中 0%', {
      modal: true,
      back: 'none',
    })
    let lastPercent = -1

    // @ts-ignore
    const downloadTask = plus.downloader.createDownload(
      info.downloadUrl,
      {
        filename: `_doc/update/${Date.now()}.apk`,
      },
      (download, status) => {
        if (waiting) {
          waiting.close()
          waiting = null
        }
        if (status === 200) {
          uni.showModal({
            title: '下载安装包完成',
            content: '点击确定后开始安装新版本',
            showCancel: false,
            success: () => {
              if (!download.filename) {
                uni.showToast({ title: '安装包路径不存在', icon: 'none' })
                reject(new Error('安装包路径不存在'))
                return
              }
              persistLatestVersion(info)
              // @ts-ignore
              plus.runtime.openFile(download.filename)
              resolve()
            },
          })
        } else {
          reject(new Error(`下载安装包失败（状态码：${status}）`))
        }
      },
    )

    downloadTask.addEventListener('statechanged', (task: any) => {
      if (task.state === 3) {
        const percent = calcProgress(task.downloadedSize, task.totalSize || info.fileSize || 0)
        if (waiting && percent !== lastPercent) {
          waiting.setTitle(`下载中 ${percent}%`)
          lastPercent = percent
        }
      }
    })

    downloadTask.start()
  })
}

/**
 * 计算下载进度
 */
function calcProgress(downloaded: number, total: number): number {
  if (!total || total <= 0) {
    return downloaded > 0 ? 50 : 0
  }
  const percent = Math.floor((downloaded / total) * 100)
  return Math.max(0, Math.min(100, percent))
}

/**
 * 打开外部链接
 */
function openExternalUrl(url?: string) {
  if (!url) {
    uni.showToast({ title: '更新地址无效', icon: 'none' })
    return
  }
  // @ts-ignore
  plus.runtime.openURL(url)
}
